#include "primitives.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>


/**
 *  ENTREES
 */

// cree une entree bidon pour pouvoir tester les types des expressions qui n'ont 
// pas d'entrees
entree* createFakeEntry(typage type)
{
	return creerEntreeBidon(type);
}




/**
 *  TABLE DES SYMBOLES
 */

// crée une table de symboles et retourne un pointeur
symtable* createSymbolTable()
{
	symtable* aux = creerSymtable();
	aux->pile = creerPilePortee();
	return aux;
}

// POP tout un level (sortie de bloc)
void popLevel(symtable* tab)
{
    //printf("appel à popLevel\n");
	tab->pile = popPortee(tab->pile);
    //printf("sortie de popLevel OK\n");
}

/**
 *  GETTERS
 */

// retourne un pointeur sur l'entree contenant le lexeme
entree* getEntry(char* lex, symtable* tab)
{
	int found = 0;
	entree* aux = tab->tete;
	entree* res = NULL;	
		
	if (aux == NULL)
	{
		found = 1;
		res = NULL;
	}	
	else if (strcmp(aux->lexeme,lex)==0)
	{
		found = 1;
		res = aux;
	}
	
	while(!found && aux->suivantTS)
	{
		aux = aux->suivantTS;
		if (strcmp(aux->lexeme,lex)==0)
		{
			found = 1;
			res = aux;
		}
	}

	return res;
}

// retourne un pointeur vers le haut de la pile de definitions d'une entree
piledef* getPileDef(entree* e)
{
	if (e)
		return e->definitioncourante;
	else
		return NULL;
}


// retourne le niveau courant (le plus élevé d'une entrée)
int getLevel(entree* e)
{
	if (getPileDef(e))
		return getMaxLevel(getPileDef(e));
	else
		return -1;
}

// retourne le compteur de registres de la table des symboles
int getCptRegister(symtable* tab)
{
    return tab->cptReg;
}





typage getType(entree* e)
{	
	if (e)
		return e->definitioncourante->tete->proprietes->type;
		//return getPileDef(e)->tete->proprietes->type;
	else
		return ERR;
}

void setType(entree* e, typage t)
{	
	if (e)
		e->definitioncourante->tete->proprietes->type = t;
	//else
		//printf("not able to set type\n");
}

param* getParams(entree* e)
{	
	if (e)
		return e->definitioncourante->tete->proprietes->listeParam;
	else
		return NULL;
}

// retourne le registre de la variable de l'entree
int getRegister(entree* e)
{	
    if (e&& e->definitioncourante && e->definitioncourante->tete && e->definitioncourante->tete->proprietes)
		if (e->definitioncourante)
			if (e->definitioncourante->tete)
				if (e->definitioncourante->tete->proprietes)
						return e->definitioncourante->tete->proprietes->reg;
    
	return -100;
}


prop* getProperties(entree* e)
{
	if (e)
		return e->definitioncourante->tete->proprietes;
	else
		return NULL;	
}

/**
 *  SETTERS
 **/


/* verifie s'il existe déjà une entrée pour le lexème
si oui, ajoute une définition à l'entrée
si non, crée l'entrée et ajoute la nouvelle définition
et ajoute cette entrée à la pile de portée */
// SI LE BLOC VAUT -1 : (constante)
// LE REGISTRE VAUT -1000
entree* addDeclaration(int bloc, char* lex,  typage t, param* liste, symtable* tab)
{
    int registre = -1000;
    if (bloc != -1)
    {
        tab->cptReg++;
        registre = tab->cptReg;
    }
    //else
        //printf("le bloc vaut -1, il s'agit d'une constante\n");

	entree* aux = getEntry(lex,tab);

    // l'entree existe déjà : on ajoute
	if(aux)
	{        
        addDefinition(bloc,aux,t,liste,registre); //MODIF : on passe le numero du bloc
	}

    // l'entree n'existe pas encore : on cree
	else
	{
        prop* p = creerPropriete(t, liste,registre) ;
        definition* def = creerDefinition(bloc, p); //MODIF : on passe le numero du bloc
		aux = creerEntree(lex, def);
		tab = ajouterEntree(aux, tab);
	}

    // ajout à la pile de définitions
    //int level = getLevel(aux);
    int level = bloc;
    //printf("ajout à la pile : lexeme %s level %i\n",lex, level);

	pileport* pilePP = addEntryToPP(tab->pile,aux,level);
	tab->pile = pilePP;
	
	return aux;
}

//ajoute un paramètre en fin de liste
void addParameter(entree* e, typage t)
{	
	prop* props =getProperties(e);	
	props->listeParam = addParameterToList(props->listeParam, t);	
	e->definitioncourante->tete->proprietes = props;	
	//return e;	
}




/**
 *  AFFICHAGES
 **/
 
void afficheType(entree* e)
{
	typage t = getType(e);
	switch(t)
	{
		case INT : printf("type INT\n"); break;
		case BOOL : printf("type BOOL\n"); break;
		case FLOAT : printf("type FLOAT\n"); break;
		case ADDRESS : printf("type ADDRESS\n"); break;
		case ERR : printf("type ERR\n"); break;
		case VOID : printf("type VOID (=procedure)\n"); break;
	}
}

void decoderType(typage t)
{
		switch(t)
	{
		case INT : printf("-------------------------------type INT\n"); break;
		case BOOL : printf("-------------------------------type BOOL\n"); break;
		case FLOAT : printf("-------------------------------type FLOAT\n"); break;
		case ADDRESS : printf("-------------------------------type ADDRESS\n"); break;
		case ERR : printf("-------------------------------type ERR\n"); break;
		case VOID : printf("-------------------------------type VOID (=procedure)\n"); break;
	}
}
